Linux C API 获取本机的 IP 地址

方法1:遍历网卡

1#include <stdio.h>      
2#include <ifaddrs.h>
3#include <arpa/inet.h>
4
5int main (void) 
6{
7    struct ifaddrs* ifAddrStruct = NULL;
8    getifaddrs(&ifAddrStruct); // 获得网卡的链表
9
10    while (ifAddrStruct!=NULL) 
11    {
12        if (ifAddrStruct->ifa_addr->sa_family==AF_INET) 
13        {
14            // IPv4
15            char address[INET_ADDRSTRLEN];
16            void* inAddr = &((struct sockaddr_in *)ifAddrStruct->ifa_addr)->sin_addr;
17            inet_ntop(AF_INET, inAddr, address, INET_ADDRSTRLEN);
18            
19            char netMask[INET_ADDRSTRLEN];
20            void* inNetMask = &((struct sockaddr_in *)ifAddrStruct->ifa_netmask)->sin_addr;
21            inet_ntop(AF_INET, inNetMask, netMask, INET_ADDRSTRLEN);
22            
23            char broadAddr[INET_ADDRSTRLEN];
24            void* inBroadAddr = &((struct sockaddr_in *)ifAddrStruct->ifa_ifu.ifu_broadaddr)->sin_addr;
25            inet_ntop(AF_INET, inBroadAddr, broadAddr, INET_ADDRSTRLEN);
26            
27            printf("IPv4 %8s: %31s \t%31s \t%31s\n", ifAddrStruct->ifa_name, address, netMask, broadAddr); 
28        } 
29        else if (ifAddrStruct->ifa_addr->sa_family==AF_INET6) 
30        {
31            // IPv6
32            char address[INET6_ADDRSTRLEN];
33            void* inAddr = &((struct sockaddr_in *)ifAddrStruct->ifa_addr)->sin_addr;
34            inet_ntop(AF_INET6, inAddr, address, INET6_ADDRSTRLEN);
35            
36            char prefixMask[INET6_ADDRSTRLEN];
37            void* inPrefixMask = &((struct sockaddr_in *)ifAddrStruct->ifa_netmask)->sin_addr;
38            inet_ntop(AF_INET6, inPrefixMask, prefixMask, INET6_ADDRSTRLEN);
39            
40            printf("IPv6 %8s: %31s \t%31s\n", ifAddrStruct->ifa_name, address, prefixMask); 
41        } 
42        ifAddrStruct=ifAddrStruct->ifa_next;
43    }
44    return 0;
45}

方法2:gethostbyname

这个方法不能支持 IPv6

1#include <stdio.h>    
2#include <unistd.h>  
3#include <netdb.h>
4#include <arpa/inet.h>
5
6int main (void) 
7{
8    // 获取 host name
9    char hostName[_SC_HOST_NAME_MAX];
10    gethostname(hostName, _SC_HOST_NAME_MAX);
11
12    // 通过 host name 获取 host entry
13    struct hostent* hostEntry = gethostbyname(hostName);
14
15    // 打印 IP 地址
16    for(int i = 0; hostEntry->h_addr_list[i]; i++) 
17    {
18        printf("%s\n", inet_ntoa(*(struct in_addr*)(hostEntry->h_addr_list[i])));
19    }
20
21    return 0;
22}

netdb.h 中还有一个 gethostent 函数,能够遍历 host entry,但是它只能查询 /etc/hosts 里的值。因此,它通常只能返回 127.0.0.1

1#include <stdio.h>    
2#include <unistd.h>  
3#include <netdb.h>
4#include <arpa/inet.h>
5
6int main(void)
7{
8    struct hostent* hostEntry;
9    while((hostEntry = gethostent()) != NULL)
10    {
11        for(int i = 0; hostEntry->h_addr_list[i]; i++) 
12        {
13            printf("%s\n", inet_ntoa(*(struct in_addr*)(hostEntry->h_addr_list[i])));
14        }
15    }
16    return 0;
17}